﻿#ifndef _C_LUAMANAGER_H_INCLUDE_
#define _C_LUAMANAGER_H_INCLUDE_

#include <QObject>
#include <QFileSystemWatcher>
#include <QTimer>

#include "../network/cwebsocketserver.h"
#include "../network/networkframemanager.h"
#include "../common/singleton.h"

#define IDD_LUA_MESSAGE_LOG            1000          // 日志信息
#define IDD_LUA_MESSAGE_UPDATELUA      1001          // 更新脚本
#define IDD_LUA_MESSAGE_RESTART        1002          // 重新运行脚本
#define IDD_LUA_MESSAGE_DEBUG          1003          // 调试脚本
#define IDD_LUA_MESSAGE_LEAVEDEBUG     1004          // 离开调试模式
#define IDD_LUA_MESSAGE_STARTDEBUG     1005          // 开始调试

/**
 * @brief The CLuaManager class lua脚本管理类，已经实现下面功能：
 * 1. 热更新代码，有本地更新和网络更新两种
 *  本地更新，通过setCurrentWorkingPath设置一个代码工作目录，程序入口在main.lua
 *  网络更新，通过压缩上传整个目录的方式实现代码热更新，主要消息协议定义：tagVersionOper
 * 2. 插件方式注册我们需要的函数，通过setRegisterDllPath来设置我们需要加载的dll目录，系统会
 * 自动搜索目录加载所有的dll.dll的实现方法参见：extends\lua_dlls\lua_extend_sys
 *
 * 使用方法：
 * CLuaManager m_LuaManager;
 * m_LuaManager->init_system("E:/software/demotest/libqtcore/extends",   //工作目录
 *                            "E:/software/demotest/libqtcore/extends/lua_dlls/bin", // dll目录
 *                            1344); // 服务器端口
 *
 */
class CLuaManager : public QObject ,
                    public NetworkFrameManager,
                    public Singleton<CLuaManager>
{
    Q_OBJECT

public:
    explicit CLuaManager(QObject *parent = nullptr);
    ~CLuaManager();

    /// 初始化系统
    bool init_system(QString workingpath,QString regdllpath="",int serverport=-1);
    /// 卸载系统
    void clean_system(void);
    /// 设置当前系统工作目录
    void setCurrentWorkingPath(QString ppath);
    /// 得到当前系统工作目录
    inline QString getCurrentWorkingPath(void) { return m_currentWorkingPath; }
    /// 设置当前脚本注册的dll所在目录
    inline void setRegisterDllPath(QString ppath) { m_currentRegisterDllPath = ppath; }
    /// 得到当前脚本注册的dll所在目录
    inline QString getRegisterDllPath(void) { return m_currentRegisterDllPath; }
    /// 得到WebSocket服务器
    inline CWebSocketServer* getWebSocketServer(void) { return &m_WebSocketServer; }

    /// 发送日志信息
    void SendLog(QString msg, QString file, int line, QString type);
    /// 发送调试信息
    void SendDebugInfo(QString msg);

#if defined (WIN32)
    /// 带参数调用指定的函数
    bool lua_function_callback(QString funcName,
                               QVariantList params=QVariantList(),
                               int returnParamCount = 0,
                               QVariantList *returnparams=&QVariantList());
#endif

    /// 网络消息处理
    //void lua_network_callback(QString socketid,QString msg);

    /// 处理网络字符串消息
    virtual void OnProcessNetText(QWebSocket *conn,QString mes);
    /// 处理网络二进制消息
    virtual void OnProcessNetBinary(QWebSocket *conn,QByteArray &data);
    /// 处理一个新的连接到达
    virtual void OnProcessConnectedNetMes(QWebSocket *conn);
    /// 处理一个连接关闭
    virtual void OnProcessDisconnectedNetMes(QWebSocket *conn);

signals:
    /// 处理日志消息
    void on_signalLog(QString msg,QString type);
    /// 重新加载并运行脚本
    void on_signalreloadandrunscript(void);

public slots:
    void WorkingdirectoryChange(const QString &path);
    void WorkingdirectoryChanged(void);
    /// 重新加载并运行脚本
    void lua_signalreloadandrunscript(void);
    /// 重新加载并运行脚本
    void reloadScriptAndRunning(void);
    /// 脚本卸载完成
    void scriptUninstallFinished(void);

private:
    /// 将指定的包数据转换到指定的文件夹
    bool Convertpackagetofolder(QByteArray packageData,QString filePath);
    /// 注册所有用到的函数
    void reg_all2luas(void);
    /// 执行指定的lua脚本
    bool exe_lua_string(const char* luastring,quint32 size);
    /// 从字符串中导入脚本
    void lua_loadscriptstring_callback(const char* scriptpath, const char* scriptstring);
    /// 初始脚本系统
    void lua_setup_callback(void);

private:
    QString m_currentWorkingPath;                     /**< 当前系统工作目录 */
    QString m_currentRegisterDllPath;                 /**< 当前脚本注册的dll所在目录 */
    QFileSystemWatcher m_pSystemWorkingPathWatcher;   /**< 用于监控系统工作目录以便于重新加载脚本 */
    QTimer *m_SystemWorkingPathTimer;                 /**< 用于过滤工作目录不停改变的情况,我们只需要最后的改变 */
    CWebSocketServer m_WebSocketServer;               /**< 网络支持 */
    int m_debugServerPort;                            /**< 网络调试服务器的端口 */
};

#endif // CLUAMANAGER_H
